/**
 * @file		dd_pmc_adc.h
 * @brief		PMC ADC driver
 * @note		None
 * @attention	None
 * 
 * <B><I>Copyright 2016 Socionext Inc.</I></B>
 */

/** @weakgroup dd_pmc_adc_overview
@{
	CM0 PMC - A/D Convertor Driver.<br>
@}*//* --- end of dd_pmc_adc_overview */

/** @weakgroup dd_pmc_adc_sequence
@{
	- @ref dd_pmc_adc_sequence_sect
	- @ref dd_pmc_adc_dma_sequence_sect
	- @ref dd_pmc_adc_sample_sect
	@section dd_pmc_adc_sequence_sect		Sequence example of start A/D conversion.
	@image html dd_pmc_adc.png
	@section dd_pmc_adc_dma_sequence_sect	Sequence example of start A/D conversion (DMA).
	@image html dd_pmc_adc_dma.png
	Interrupt signal of AD is shared with the transfer request DMA.<br>
	When you use the AD DMA, please disable AD interrupts in the interrupt controller of the LSI TOP.
	@section dd_pmc_adc_sample_sect			Sample code
	The example of ADC is as follows.
	@code
	void ADC_Sample()
	{
		INT32	result;
		T_DD_PMC_ADC_CTRL adc_ctrl;

		Dd_PMC_ADC_Init();
		if( trigger == 0 ){  // Start by software trigger
			// Single conversion
			adc_ctrl.ch			= D_DD_PMC_ADC_CH_0 | D_DD_PMC_ADC_CH_1 | D_DD_PMC_ADC_CH_2 | D_DD_PMC_ADC_CH_3 | D_DD_PMC_ADC_CH_4 | D_DD_PMC_ADC_CH_5 | D_DD_PMC_ADC_CH_6;	// All chanel
			adc_ctrl.cnv_mode	= E_DD_PMC_ADC_CONV_MODE_SINGLE;	// Single conversion
			adc_ctrl.start_trig	= E_DD_PMC_ADC_START_TRIG_SOFT;		// Soft trigger
			adc_ctrl.timer_trig	= E_DD_PMC_ADC_TIMER_TRIG_NONE;		// No trigger
			adc_ctrl.powerdown	= 0;								// Auto power down is enable
			adc_ctrl.tsel		= E_DD_PMC_ADC_TSEL_INTERRUPT;		// Start by timer interrupt(Don't care)
			adc_ctrl.sampling_time	= 0xBB;							// Sampling time
			adc_ctrl.cmp_data	= 0;								// Comparison data none

			Dd_PMC_ADC_Ctrl(&adc_ctrl);

			// 5ms wait after XPD = on
			
			Dd_PMC_ADC_Start(NULL);

		}
		else if( trigger == 1 ){  // Start by timer trigger
			// Single conversion
			adc_ctrl.ch			= D_DD_PMC_ADC_CH_0;				// 0 chanel
			adc_ctrl.cnv_mode	= E_DD_PMC_ADC_CONV_MODE_SINGLE;	// Single conversion
			adc_ctrl.start_trig	= E_DD_PMC_ADC_START_TRIG_TIMER;  	// Timer trigger
			adc_ctrl.timer_trig	= E_DD_PMC_ADC_TIMER_TRIG_1;		// trigger
			adc_ctrl.powerdown	= 0;								// Auto power down is enable
			adc_ctrl.tsel		= E_DD_PMC_ADC_TSEL_INTERRUPT;		// Start by timer interrupt
			adc_ctrl.sampling_time	= 0xBB;							// Sampling time
			adc_ctrl.cmp_data	= 0;								// Comparison data none
			
			Dd_PMC_ADC_Ctrl(&adc_ctrl);
			
			// Set Timer
			Dd_PMC_ADC_Set_Timer(1000);								// Conversion cycle time : 1000[usec]
			
			// DMA setting
			Dd_PMC_ADC_Set_DMA_Transfer(0xXXXXXXXX);				// Destination SRAM Address : 0xXXXXXXXX
			
			Dd_PMC_ADC_Start(sample_adc_cb);
			
			// Run the A/D Conversion.
			
			Dd_PMC_ADC_Stop();
		}
	}
	@endcode

@}*//* --- end of dd_pmc_adc_sequence */

#ifndef _DD_PMC_ADC_H_
#define _DD_PMC_ADC_H_

/** @weakgroup dd_pmc_adc_definition
@{*/

#include "driver_common.h"

/*----------------------------------------------------------------------*/
/* Definition															*/
/*----------------------------------------------------------------------*/
#define D_DD_PMC_ADC_INPUT_PARAM_ERR	(D_DD_PMC_ADC | D_DDIM_INPUT_PARAM_ERROR)	/**< Input Parameter Error */
#define D_DD_PMC_ADC_DMA_SS_ERROR		(D_DD_PMC_ADC | D_DDIM_STATUS_ABNORMAL)		/**< ADC DMA stop status error. */

#define D_DD_PMC_ADC_NUM		(8)				/**< Number of ADC channels.	*/

#define D_DD_PMC_ADC_CH_0		(0x00000001)	/**< ADC 0 channel.				*/
#define D_DD_PMC_ADC_CH_1		(0x00000002)	/**< ADC 1 channel.				*/
#define D_DD_PMC_ADC_CH_2		(0x00000004) 	/**< ADC 2 channel.				*/
#define D_DD_PMC_ADC_CH_3		(0x00000008) 	/**< ADC 3 channel.				*/
#define D_DD_PMC_ADC_CH_4		(0x00000010) 	/**< ADC 4 channel.				*/
#define D_DD_PMC_ADC_CH_5		(0x00000020) 	/**< ADC 5 channel.				*/
#define D_DD_PMC_ADC_CH_6		(0x00000040) 	/**< ADC 6 channel.				*/
#define D_DD_PMC_ADC_CH_7		(0x00000080) 	/**< ADC 7 channel.				*/

/*----------------------------------------------------------------------*/
/* Enumeration															*/
/*----------------------------------------------------------------------*/
/** ADC conversion mode selection. */
typedef enum {
	E_DD_PMC_ADC_CONV_MODE_SINGLE = 0,	/**< Single conversion						*/
	E_DD_PMC_ADC_CONV_MODE_CONTINUE,	/**< Continuous conversion					*/
	E_DD_PMC_ADC_CONV_MODE_CONT_LOW,	/**< Convert continuously until low level	*/
	E_DD_PMC_ADC_CONV_MODE_CONT_HIGH	/**< Convert continuously until high level	*/
} E_DD_PMC_ADC_CONV_MODE;

/** ADC start trigger selection. */
typedef enum {
	E_DD_PMC_ADC_START_TRIG_NOT_PERFORMED	= 0,	/**< Startup is not performed	*/
	E_DD_PMC_ADC_START_TRIG_TIMER			= 1,	/**< Trigger by timer			*/
	E_DD_PMC_ADC_START_TRIG_SOFT			= 2,	/**< Trigger by soft			*/
	E_DD_PMC_ADC_START_TRIG_BOTH			= 3,	/**< Trigger by both			*/
	E_DD_PMC_ADC_START_TRIG_EXT				= 4		/**< Trigger by AD external		*/
} E_DD_PMC_ADC_START_TRIG;

/** ADC timer trigger selection. */
typedef enum {
	E_DD_PMC_ADC_TIMER_TRIG_NONE = 0,	/**< No trigger by 32 bit reload timer		*/
	E_DD_PMC_ADC_TIMER_TRIG_0			/**< Triggered by 32 bit reload timer 0		*/
} E_DD_PMC_ADC_TIMER_TRIG;

/** ADC start by timer trigger selection. */
typedef enum {
	E_DD_PMC_ADC_TSEL_INTERRUPT = 0,	/**< Start by timer interrupt				*/
	E_DD_PMC_ADC_TSEL_TOGGLE			/**< Start by timer toggle output			*/
} E_DD_PMC_ADC_TSEL;

/** ADC start external trigger edge selection. */
typedef enum {
	E_DD_PMC_ADC_EXT_TRIG_EDGE_FALL = 0,/**< AD external trigger is fall edge		*/
	E_DD_PMC_ADC_EXT_TRIG_EDGE_RISE		/**< AD external trigger is rise edge		*/
} E_DD_PMC_ADC_EXT_TRIG_EDGE;

/*----------------------------------------------------------------------*/
/* Structure  															*/
/*----------------------------------------------------------------------*/
/** Sampling value collecting structure. */
typedef struct {
	USHORT	data[D_DD_PMC_ADC_NUM];		/**< AD data of each channel	*/
} T_DD_PMC_ADC_DATA;

/** ADC control information structure. */
typedef struct {
	SHORT						ch;				/**< Channel number (ADC0 range of 0~6, ADC1 range of 0~5). <br>
													 You can specify plural channels at one time by taking logical addition for the channels which you want to set.<br>
													 For example, if you set channel 0 and 1 and 2, please set 0x00000111 to the channel number. */
	E_DD_PMC_ADC_CONV_MODE		cnv_mode;		/**< Conversion mode					*/
	E_DD_PMC_ADC_START_TRIG		start_trig;		/**< Start trigger selection			*/
	E_DD_PMC_ADC_TIMER_TRIG		timer_trig;		/**< Timer trigger selection			*/
	E_DD_PMC_ADC_TSEL			tsel;			/**< Timer trigger selection			*/
	E_DD_PMC_ADC_EXT_TRIG_EDGE	ext_edge;		/**< External trigger edge selection	*/
	UCHAR						sampling_time;	/**< Sampling time						*/
	UCHAR						powerdown;		/**< Auto power down control.<br>
													 &nbsp;0 : Auto power down is enable<br>
													 &nbsp;1 : Auto power down is disable */
	USHORT						cmp_data;		/**< AD comparison data	(max:0x3ff)		*/
} T_DD_PMC_ADC_CTRL;

/*----------------------------------------------------------------------*/
/* Grobal Data															*/
/*----------------------------------------------------------------------*/
// Nothing Special

/*----------------------------------------------------------------------*/
/* Macro																*/
/*----------------------------------------------------------------------*/
// Nothing Special

/* @} */	// dd_pmc_adc_definition group

/** @weakgroup dd_pmc_adc_api
@{*/
/*----------------------------------------------------------------------*/
/* Function																*/
/*----------------------------------------------------------------------*/
#ifdef __cplusplus
extern "C" {
#endif

/**
The clock supply of ADC begins. Moreover, the sampling variable is initialized.
*/
extern VOID Dd_PMC_ADC_Init( VOID );

/**
The ADC control condition is set.<br>
Please set the logical add of the channel number of the controlled object.
@param [in]		adc_ctrl	ADC control information structure. See @ref T_DD_PMC_ADC_CTRL.
@retval D_DDIM_OK					OK
@retval D_DD_PMC_ADC_INPUT_PARAM_ERR	Input Parameter Error
@remarks	Please refer to the following for the details between conversion mode and another parameters.<br><br>
<table>
	<tr>
	  <th>cnv_mode</th>
	  <th>start_trig</th>
	  <th>timer_trig</th>
	  <th>tsel</th>
	  <th>sampling_time</th>
	  <th>powerdown</th>
	  <th>cmp_data</th>
	  <th>callback</th>
	</tr>
	<tr>
	  <td>@ref E_DD_PMC_ADC_CONV_MODE_SINGLE</td>
	  <td>O</td>
	  <td>*1</td>
	  <td>*1</td>
	  <td>O</td>
	  <td>O</td>
	  <td>-</td>
	  <td>*2</td>
	</tr>
	<tr>
	  <td>@ref E_DD_PMC_ADC_CONV_MODE_CONTINUE</td>
	  <td>O</td>
	  <td>*1</td>
	  <td>*1</td>
	  <td>O</td>
	  <td>-</td>
	  <td>-</td>
	  <td>*2</td>
	</tr>
	<tr>
	  <td>@ref E_DD_PMC_ADC_CONV_MODE_CONT_LOW</td>
	  <td>O</td>
	  <td>*1</td>
	  <td>*1</td>
	  <td>O</td>
	  <td>-</td>
	  <td>O</td>
	  <td>*2</td>
	</tr>
	<tr>
	  <td>@ref E_DD_PMC_ADC_CONV_MODE_CONT_HIGH</td>
	  <td>O</td>
	  <td>*1</td>
	  <td>*1</td>
	  <td>O</td>
	  <td>-</td>
	  <td>O</td>
	  <td>*2</td>
	</tr>
</table>
<br>
&nbsp;*1 :If @ref E_DD_PMC_ADC_START_TRIG_TIMER or @ref E_DD_PMC_ADC_START_TRIG_BOTH is specified in start_trig, it is necessary to specify it.<br>
&nbsp;*2 :User can set this parameter arbitrarily.<br>
<hr>
*/
extern INT32 Dd_PMC_ADC_Ctrl( T_DD_PMC_ADC_CTRL const* const adc_ctrl );

/**
The ADC control condition is get.
@param [out]	adc_ctrl	ADC control information structure. See @ref T_DD_PMC_ADC_CTRL.
@retval D_DDIM_OK					OK
@retval D_DD_PMC_ADC_INPUT_PARAM_ERR	Input Parameter Error
*/
extern INT32 Dd_PMC_ADC_Get_Ctrl( T_DD_PMC_ADC_CTRL* const adc_ctrl );

/**
Set a timer that triggers of AD conversion.
@param [in]		conv_cycle	conversion cycle time (micro second).
@retval D_DDIM_OK					OK
@retval D_DD_PMC_ADC_INPUT_PARAM_ERR	Input Parameter Error
*/
extern INT32 Dd_PMC_ADC_Set_Timer( ULONG conv_cycle );

/**
To set a DMA transfer.
@param [in]		sram_address	Destination SRAM Address.
@retval D_DDIM_OK					OK
@retval D_DD_PMC_ADC_INPUT_PARAM_ERR	Input Parameter Error
*/
extern INT32 Dd_PMC_ADC_Set_DMA_Transfer( ULONG sram_address );

/**
The analog to digital translation is started with a soft trigger.
@param [in]		callback	Callback function pointer.
@remarks	In @ref Dd_PMC_ADC_Ctrl, start_trig=1: When beginning is set at the timer interrupt opportunity, the start with this API is unnecessary.<br>
			Please start the corresponding 32bit reload timer (Refer to API specifications of @ref dd_pmc_tmr32 for details).<br>
			Please always call this function about 5ms after the set by Dd_PMC_ADC_Ctrl.
*/
extern VOID Dd_PMC_ADC_Start( VP_CALLBACK callback );

/**
The analog to digital translation is stopped.
*/
extern VOID Dd_PMC_ADC_Stop( VOID );

/**
The clock supply to ADC is stopped.
*/
extern VOID Dd_PMC_ADC_Terminate( VOID );

/**
The analog to digital translation value sampled in the analog to digital translation regardless of is returned.
@param [out]	adc_data	Sampling value buffer address. See @ref T_DD_PMC_ADC_DATA.
*/
extern VOID Dd_PMC_ADC_Get_Value( T_DD_PMC_ADC_DATA* const adc_data );

/**
The analog to digital translation value sampled in the analog to digital translation regardless of is returned.
@param [in]		ch			channel number (ADC range of 0~6)
@param [out]	adc_data	ADC data
*/
extern VOID Dd_PMC_ADC_Get_Value_By_Ch( UCHAR ch, USHORT* const adc_data );

/**
The interruption flag is cleared, and the callBack function is called.
@remarks	Only an interruption clear flag of CallBack when it is unregistered.<br>
*/
extern VOID Dd_PMC_ADC_Int_Handler( VOID );

#ifdef __cplusplus
}
#endif

/* @} */	// dd_pmc_adc_api group

#endif	// _DD_PMC_ADC_H_
